#ifndef _HASH_H_
#define _HASH_H_

/**********************************************************************
 * Hash.h
 * 
 * Descripcion :Esta clase representa un archivo de datos que utiliza
 * un indice primario hash, y puede tener un indice secundario.
*********************************************************************/

#include "arch_datos.h"
#include "arch_espacios_libres.h"
#include "arch_tabla_dispersion.h"
#include "header.h"
#include "bloque.h"
#include "buffer.h"
#include "debugger.h"
#include "funcionHash.h"
#include "excep_consulta_hash.h"

#define EXT_EELL 				".esp"
#define TAM_OCUPADO_CABECERA	8
#define TAM_EELL_BUCKETS		128
#define EXT_TABLA_DISP			".ht"
#define TAM_TAG_PROF			sizeof(unsigned int)

class Hash : public ArchivoDatos{
	
	//Atributos del archivo secuencial
	
	private:
		
		ArchEspaciosLibres * buckets_libres; //Referencia al archivo de bloques libres
		ArchTablaDispersion* tabla; //tabla de dispersion
		
		//Constructor de copia privado para que no se pueda copiar un archivo
		Hash(Hash &s);
		
		void ingresar_interno(TipoStruct * reg, bool reinserto) throw(ExcepArchCerrado,ExcepRegExistente, ExcepBloqueTam);
		
	public:
	
		Hash(std::string& nombre, unsigned int tam_bloque, unsigned int tam_bloque_indice);
	
		~Hash();
	
		//Metodos heredados de la interfaz de archivo
		
		void abrir() throw(ExcepAbriendoArch);
				
		void crear(std::string formato) throw(ExcepCreandoArch, ExcepSintaxisParser, ExcepBloqueTam); 
		
		void cerrar();
		
		void ingresar(TipoStruct * reg) throw(ExcepArchCerrado,ExcepRegExistente, ExcepBloqueTam);
		
		void quitar(std::vector<ParesDatos*> &elementos, std::vector<TipoStruct*> &resultado) throw(ExcepArchCerrado);
		
		void consultar(std::vector<ParesDatos*> &consultas, std::vector<TipoStruct*> &resultado)
									 throw(ExcepArchCerrado,ExcepLeerBloque);
 		
 		void actualizar(TipoStruct * reg) throw(ExcepArchCerrado,ExcepRegInexistente, ExcepBloqueTam);
 													
 		TiposArchivo get_tipo_archivo();		
 		
 		void eliminar ();		
 		
 		/*
 		 * Devuelve el tamanio libre del archivo en cantidad de bytes.
 		 */
 		unsigned int get_espacio_libre() throw(ExcepArchCerrado, ExcepLeerBloque);
 		
 		/*
 		 * Devuelve el espacio libre en bytes del indice primario.
 		 */ 
 		virtual unsigned int get_esp_libre_indice()  throw(ExcepArchCerrado, ExcepLeerBloque);
 		 
 		/*
 		 * Devuelve la cantidad de registros del indice primario.
 		 */ 										
 		virtual unsigned int get_cant_regs_indice() throw(ExcepArchCerrado);
 		
 		/*
 		 * Devuelve el tamanio ocupado total por el indice primario, en bytes.
 		 */ 
 		virtual long get_tam_arch_indice() throw(ExcepArchCerrado);
 		 
		/*
		 * Imprime el contenido del hash.
		 */
 		void map_hash();

 	//Metodos de uso interno del archivo Hash	
 		
 	private:
		/*
		 * Dada una ref a un bloque, se encarga de obtener la prifundidad
		 * del mismo.
		 */
		unsigned int get_profundidad(Bloque* bloque);
		
		/*
		 * Dada una ref a un bloque y una profundidad (POTENCIA DE 2)
		 * le asigna al bloque la misma.
		 */ 
		void set_profundidad(Bloque * bloque, unsigned int prof);
		
		/*
		 * Dada una ref a un bloque actualiza la profundidad en el mismo 
		 * duplicandola
		 */
		void duplicar_profundidad(Bloque* bloque);	
		
		/*
		 * Dada una ref a un bloque actualiza la profundidad en el mismo 
		 * dividiendola por dos, quedando la mitad de la misma
		 */
		void dividir_profundidad(Bloque* bloque);	
		
		/*
		 * Dado un bloque, y la pos y tamanio de un reg, saca el reg del bloque y decrementa la cant
		 * de registros en el bloque.
		 */
		int sacar_reg_bloque(Bloque* bloque, TipoStruct * reg, unsigned int pos_reg, unsigned int tam_reg);
		
		/*
		 * Dados un bloque y un reg pasado por param, serializa el reg y lo pone en el bloque al final
		 * del mismo si este entra. Sino maneja un overflow. Devuelve true.
		 */
 		bool poner_reg_en_bloque(Bloque* bloque, TipoStruct* reg);

		/*
		 * Devuelve un bloque libre para llenarlo con elementos. Primero
		 * busca en el archivo de EELL si habia uno y si no lo crea.
		 */ 
		Bloque * obtener_bloque_nuevo(Bloque * bloque);

		/*
		 * Devuelve el bloque en el que deberia estar el registro pasado por parametro
		 */		
		Bloque* get_bloque(TipoStruct * reg);
		
		/*
		 * Quita todos los elementos del bloque, y junto con el reg pasado
		 * por parametro los vuelve a ingresar
		 */ 
		void redistribur(Bloque * bloque, TipoStruct *reg);
 		
 		/*
 		 * Contiene toda la logica del manejo del underflow
 		 */
 		 void manejar_underflow(Bloque * bloque, unsigned int e_tabla_viejo);
 		
 		/*
 		 * Contiene toda la logica del manejo del overflow
 		 */
 		 void manejar_overflow(Bloque * bloque, TipoStruct * reg);
 		
 		/*
 		 * Si el bloque es el ultimo lo elimina del archivo.
 		 * Si no es el ultimo lo intercambia con este y lo elimina.
 		 */
 		void eliminar_bloque (Bloque* bloque);
		
		/*
		 * Devuelve la primera posicion donde se encuentran los registros
		 * en el archivo, es decir, luego de los tags de control
		 */ 
		unsigned int get_primera_pos(){
			return TAM_TAG_PROF;
		}
		
};

#endif
